# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
import model.app_config
import urllib
import util


EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'


class RietveldRequestError(Exception):
  """Raised on request errors."""
  pass


class Rietveld(object):
  """Implements a Python API to access rietveld via HTTP.

  Authentication is handled via an OAuth2 access token minted from an RSA key
  associated with a service account (which can be created via the Google API
  console). For this to work, the Rietveld instance to talk to must be
  configured to allow the service account client ID as OAuth2 audience (see
  Rietveld source). Both the RSA key and the server URL are provided via static
  application configuration.
  """

  def __init__(self):
    self.app_config = model.app_config.get()

  @util.lazy_property
  def http(self):
    http = httplib2.Http()

    creds = SignedJwtAssertionCredentials(self.app_config.client_id,
                                          self.app_config.service_account_key,
                                          EMAIL_SCOPE)
    creds.authorize(http)
    return http

  @util.lazy_property
  def xsrf_token(self):
    return self.make_request('xsrf_token',
                             headers={'X-Requesting-XSRF-Token': 1})

  def make_request(self, req, *args, **kwargs):
    resp, response = self.http.request(
        '%s/%s' % (self.app_config.server_url, req), *args, **kwargs)
    if resp.status != 200:
      raise RietveldRequestError(
          'Rietveld %s request failed: %s\n%s' %
          (req, resp.status, str(resp)), resp, response)

    return response

  def post_data(self, req, payload=None):
    actual_payload = dict(payload or {})
    actual_payload['xsrf_token'] = self.xsrf_token

    return self.make_request(req, method='POST',
                             body=urllib.urlencode(actual_payload))

  def post_issue_data(self, issue, req, payload):
    return self.post_data('%s/%s' % (issue, req), payload)

  def publish_inline_comments(self, issue, comment, reviewers, cc,
                              subject=None, send_mail=False):
    publish_payload = {
        'cc': cc,
        'message': comment,
        'message_only': 0,
        'no_redirect': 1,
        'reviewers': reviewers,
        'send_mail': 1 if send_mail else 0,
    }
    if subject is not None:
      publish_payload['subject'] = subject
    self.post_issue_data(issue, 'publish', publish_payload)

  def add_inline_comment(self, issue_id, patchset_id, patch_id, line, a_or_b,
                         comment):
    comment_payload = {
        'snapshot': 'old' if a_or_b is 'a' else 'new',
        'lineno': line,
        'side': a_or_b,
        'issue': issue_id,
        'patchset': patchset_id,
        'patch': patch_id,
        'text': comment,
    }
    self.post_data('inline_draft', comment_payload)
